//==============================================================================
//
//  File        : mmpf_uart.c
//  Description : Firmware UART Control Function
//  Author      : Penguin Torng
//  Revision    : 1.0
//
//==============================================================================

#include "includes_fw.h"
#include "mmpf_uart.h"

#include "mmp_reg_uart.h"
#include "lib_retina.h"
//#include "config_fw.h"

//==============================================================================
//
//                              VARIABLES
//
//==============================================================================


#if (UART_RXINT_MODE_EN == 1)
static MMP_BYTE         m_bDebugRxStrBuf[RX_QUEUE_SIZE];
static MMP_ULONG        m_bDebugRxStrLen = 0;
static UartCallBackFunc *m_UartRx_CallBack[MMPF_UART_MAX_COUNT];
#endif
static MMPF_OS_SEMID    m_UartSemID[MMPF_UART_MAX_COUNT];

#if UART_DMA_MODE_EN
static UartCallBackFunc *m_UartDma_CallBack[MMPF_UART_MAX_COUNT];
static MMP_SHORT	m_bUartDmaInUsedId = MMPF_UART_MAX_COUNT;
#endif
MMP_BOOL	ubDisableUartSW = MMP_FALSE;
//==============================================================================
//
//                              FUNCTION PROTOTYPES
//
//==============================================================================


#if (UART_DMA_MODE_EN == 1)
//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_SwitchToDmaMode
//  Description :
//  Note        : This is the 1st step of UART using DMA mode
//------------------------------------------------------------------------------
/** @brief This function set the UART device from normal mode to DMA mode.

This function set the UART device from normal mode to DMA mode.
@param[in] uartId indicate which UART device, please refer the data structure of MMPF_UART_ID
@param[in] bEnable stands for enable switch to DMA mode or back from DMA mode.
@return It reports the status of the operation.
*/
MMP_ERR MMPF_Uart_SwitchToDmaMode(MMPF_UART_ID uartId, MMP_BOOL bEnable)
{
    AITPS_UARTB	pUART  = AITC_BASE_UARTB;
    if (bEnable == MMP_TRUE) {
        #if (UART_RXINT_MODE_EN == 1)
        pUART->US[uartId].US_IER &= (~US_RX_FIFO_OVER_THRES);  //close uart RX normal interrupt
        #endif

        #if (UART_DMA_MODE_EN == 1)
        MMPF_OS_AcquireSem(m_UartSemID[uartId], 0x0);
        m_bUartDmaInUsedId = uartId;
        #endif
    }
    else {
        if (uartId == m_bUartDmaInUsedId) {
            //Clean DMA mode settings
            pUART->US[uartId].US_CR &= US_DMA_CLEAN;

            #if (UART_DMA_MODE_EN == 1)
            MMPF_OS_ReleaseSem(m_UartSemID[uartId]);
            m_bUartDmaInUsedId = MMPF_UART_MAX_COUNT;
            #endif

            #if (UART_RXINT_MODE_EN == 1)
            pUART->US[uartId].US_IER = US_RX_FIFO_OVER_THRES;  //Resume uart RX normal interrupt
            #endif
        }
    }
    return MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_SetTxDmaMode
//  Description :
//  Note        : This is the 2nd step of UART using DMA TX mode
//------------------------------------------------------------------------------
/** @brief This function set the parameters using by UART DMA TX mode.

This function set the parameters using by UART DMA Tx mode.
@param[in] uartId indicate which UART device, please refer the data structure of MMPF_UART_ID
@param[in] MMPF_UART_DMAMODE indicate which DMA mode to be used, please refer the data structure MMPF_UART_DMAMODE.
@param[in] uartTxStartAddr indicate the Tx DMA start address.
@param[in] uartTxTotalByte indicate number of bytes would be sent (start from start address).
@return It reports the status of the operation.
*/
MMP_ERR MMPF_Uart_SetTxDmaMode(MMPF_UART_ID uartId, MMPF_UART_DMAMODE uartDmaMode, MMP_ULONG uartTxStartAddr, MMP_USHORT uartTxTotalByte)
{
	AITPS_UARTB	pUART  = AITC_BASE_UARTB;
	
	if( m_bUartDmaInUsedId != uartId) {
		RTNA_DBG_Str(0, "uart Device have not got the DMA resource !!\r\n");
		return MMP_ERR_NONE;
	}
	
	if (uartDmaMode == MMPF_UART_TXDMA) {
		pUART->US[uartId].US_TXDMA_START_ADDR = uartTxStartAddr;
		pUART->US[uartId].US_TXDMA_TOTAL_BYTE = uartTxTotalByte;
	}
	else {
		RTNA_DBG_Str(0, "MMPF_Uart_SetRxDmaMode(): Error TX DMA mode \r\n");
		return MMP_ERR_NONE;
	}
	
	return MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_SetRxDmaMode
//  Description :
//  Note        : This is the 2nd step of UART using DMA RX mode
//------------------------------------------------------------------------------
/** @brief This function set the parameters using by UART DMA RX mode.

This function set the parameters using by UART DMA Tx mode.
@param[in] uartId indicate which UART device, please refer the data structure of MMPF_UART_ID
@param[in] MMPF_UART_DMAMODE indicate which DMA mode to be used, please refer the data structure MMPF_UART_DMAMODE.
@param[in] uartRxStartAddr indicate the RX DMA start address.
@param[in] uartRxEndAddr indicate the RX DMA End address.
@param[in] uartRxLowBoundAddr indicate the RX lower bound address (Using by RX DMA Ring Mode). 
@return It reports the status of the operation.
*/
MMP_ERR MMPF_Uart_SetRxDmaMode(MMPF_UART_ID uartId, MMPF_UART_DMAMODE uartDmaMode, MMP_ULONG uartRxStartAddr, MMP_ULONG uartRxEndAddr, MMP_ULONG uartRxLowBoundAddr)
{
	AITPS_UARTB	pUART  = AITC_BASE_UARTB;
	
	if( m_bUartDmaInUsedId != uartId) {
		RTNA_DBG_Str(0, "uart Device have not got the DMA resource !!\r\n");
		return MMP_ERR_NONE;
	}
	
	if ((uartDmaMode == MMPF_UART_RXDMA) || (uartDmaMode == MMPF_UART_RXDMA_RING)) {
		pUART->US[uartId].US_RXDMA_START_ADDR = uartRxStartAddr;
		pUART->US[uartId].US_RXDMA_END_ADDR = uartRxEndAddr;
		if(uartDmaMode == MMPF_UART_RXDMA_RING) {
			pUART->US[uartId].US_RXDMA_LB_ADDR = uartRxLowBoundAddr;
		}	
	}
	else {
		RTNA_DBG_Str(0, "MMPF_Uart_SetRxDmaMode(): Error RX DMA mode \r\n");
		return MMP_ERR_NONE;
	}
	
	return MMP_ERR_NONE;
}


//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_SetDmaInterruptMode
//  Description :
//  Note        : This is the step of UART using DMA interrupt mode settings. (This step can be done betwee step2 and step3)
//------------------------------------------------------------------------------
/** @brief This function sets the UART DMA interrupt mode.

This function sets the UART DMA interrupt mode.
@param[in] uartId indicate which UART device, please refer the data structure of MMPF_UART_ID
@param[in] MMPF_UART_DMA_INT_MODE indicate which DMA interrupt mode to be used, please refer the data structure MMPF_UART_DMA_INT_MODE.
@param[in] bEnable stands for "enable the related interrupt mode or not".
@param[in] callBackFunc is used as interrupt handler.
@param[in] uartRxThreshold is used by RX DMA mode, when dma count reaches the Threshold and the related interrupt occurs. 
@return It reports the status of the operation.
*/
MMP_ERR MMPF_Uart_SetDmaInterruptMode (MMPF_UART_ID uartId, MMPF_UART_DMA_INT_MODE intMode, MMP_BOOL bEnable, UartCallBackFunc* callBackFunc, MMP_USHORT uartRxThreshold)
{
	AITPS_UARTB	pUART  = AITC_BASE_UARTB;
	if (bEnable == MMP_TRUE) {
		switch (intMode) {
			case MMPF_UART_TXDMA_FINISH_IENABLE:
				pUART->US[uartId].US_IER |= US_TXDMA_FINISH_IENABLE;
				break;
			case MMPF_UART_RXDMA_THR_IEABLE:
				pUART->US[uartId].US_RXDMA_TOTAL_THR = uartRxThreshold;
				pUART->US[uartId].US_IER |= US_RXDMA_THR_IEABLE;
				break;
			case MMPF_UART_RXDMA_WRITEMEM_IENALBE:
				pUART->US[uartId].US_IER |= US_RXDMA_WRITEMEM_IENALBE;
				break;
			case MMPF_UART_RXDMA_DROPDATA_IENALBE:
				pUART->US[uartId].US_IER |= US_RXDMA_DROPDATA_IENALBE;
				break;
			default:
				RTNA_DBG_Str(0, "Error Dma Interrupt Mode ! \r\n");
				return MMP_ERR_NONE;
				break;
		}
		
		if (callBackFunc != NULL) {	
			m_UartDma_CallBack[intMode] = callBackFunc;
		}
	}
	else {
		switch (intMode) {
			case MMPF_UART_TXDMA_FINISH_IENABLE:
				pUART->US[uartId].US_IER &= (~US_TXDMA_FINISH_IENABLE);
				break;
			case MMPF_UART_RXDMA_THR_IEABLE:
				pUART->US[uartId].US_RXDMA_TOTAL_THR = 0;
				pUART->US[uartId].US_IER &= (~US_RXDMA_THR_IEABLE);
				break;
			case MMPF_UART_RXDMA_WRITEMEM_IENALBE:
				pUART->US[uartId].US_IER &= (~US_RXDMA_WRITEMEM_IENALBE);
				break;
			case MMPF_UART_RXDMA_DROPDATA_IENALBE:
				pUART->US[uartId].US_IER &= (~US_RXDMA_DROPDATA_IENALBE);
				break;
			default:
				RTNA_DBG_Str(0, "Error Dma Interrupt Mode ! \r\n");
				return MMP_ERR_NONE;
				break;
		}	
		m_UartDma_CallBack[intMode] = NULL;
	}
	return MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_EnableDmaMode
//  Description :
//  Note        : This function is the 3rd step of UART DMA settings.
//------------------------------------------------------------------------------
/** @brief This function is used to enable or disable UART DMA mode.

This function is used to enable or disable UART DMA mode.
@param[in] uartId indicate which UART device, please refer the data structure of MMPF_UART_ID
@param[in] MMPF_UART_DMAMODE indicate which DMA mode to be used, please refer the data structure MMPF_UART_DMAMODE.
@param[in] bEnable stands for "enable the related mode or not".
@return It reports the status of the operation.
*/
MMP_ERR MMPF_Uart_EnableDmaMode(MMPF_UART_ID uartId, MMPF_UART_DMAMODE uartDmaMode, MMP_BOOL bEnable)
{
    AITPS_UARTB	pUART  = AITC_BASE_UARTB;

    if (bEnable == MMP_TRUE) {
        switch (uartDmaMode) {
            case MMPF_UART_RXDMA_RING:
                pUART->US[uartId].US_CR |= US_RXDMA_RING_ENABLE;
                break;
            case MMPF_UART_TXDMA:
                pUART->US[uartId].US_CR |= US_TXDMA_ENABLE;
                break;
            case MMPF_UART_RXDMA:
                pUART->US[uartId].US_CR |= US_RXDMA_ENABLE;
                break;
            default:
                RTNA_DBG_Str(0, "Error! wrong DMA mode enable !\r\n");
                break;
        }
    }
    else {
        switch (uartDmaMode) {
            case MMPF_UART_RXDMA_RING:
                pUART->US[uartId].US_CR &= (~US_RXDMA_RING_ENABLE);
                break;
            case MMPF_UART_TXDMA:
                pUART->US[uartId].US_CR &= (~US_TXDMA_ENABLE);
                break;
            case MMPF_UART_RXDMA:
                pUART->US[uartId].US_CR &= (~US_RXDMA_ENABLE);
                break;
            default:
                RTNA_DBG_Str(0, "Error! wrong DMA mode disable !\r\n");
                break;
        }
    }
	
    return MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_RxDmaStart
//  Description :
//  Note        : This operation need to be done after settings done or DMA RX restart.
//------------------------------------------------------------------------------
/** @brief This function to enable UART DMA RX operations.

This function to enable UART DMA RX operations.
@param[in] uartId indicate which UART device, please refer the data structure of MMPF_UART_ID
@return It reports the status of the operation.
*/
MMP_ERR MMPF_Uart_RxDmaStart(MMPF_UART_ID uartId)
{
	AITPS_UARTB	pUART  = AITC_BASE_UARTB;
	pUART->US[uartId].US_CR |= US_RXDMA_START_FLAG;
	return MMP_ERR_NONE;
}
#endif

#if UART_RXINT_MODE_EN
static PUARTCOMMAND sUartCmdListArray[MAX_NUMBER_OF_UART_CMD_LIST];
static int uiUartCmdListNumber = 0;
static MMP_BOOL m_UartRxEnable[MMPF_UART_MAX_COUNT];
static MMP_BOOL m_UartInDmaMode[MMPF_UART_MAX_COUNT];

void UartCmdListAll( char* szParam )
{
    int i;

    for(i=0; i< uiUartCmdListNumber; i++) {
        PUARTCOMMAND psCmd = sUartCmdListArray[i];

    	while(psCmd->szCommandString != NULL) {
    		if(psCmd->szHelp == NULL) {}

    		dbg_printf(3, "%s\t- %s\r\n", psCmd->szCommandString, psCmd->szHelp);
    		psCmd++;
    	}
    }
}

void UartCmdJWTest( char* szParam )
{
    //dbg_printf(3,"Hello AIT!\r\n");
	//KK_Debug4("TEST");
}

#ifdef ZDW_BARCODE
void UartTriggerScan( char* szParam )
{
}
#endif

static  UARTCOMMAND sUartCommand[] =
{
    { "ls",     "",     "Show command list.",   UartCmdListAll},
    { "test",   "",           "JengWei test",   UartCmdJWTest },
#ifdef ZDW_BARCODE
//	{ "FF540D", "", "Trigger Scan", UartTriggerScan},
#endif
    {0,0,0,0}
};

MMP_BOOL UartRegisterUartCmdList( PUARTCOMMAND pUartCmdList )
{
    // Check if the array is full.
    if(uiUartCmdListNumber >= MAX_NUMBER_OF_UART_CMD_LIST) {
        return FALSE;
    }

    sUartCmdListArray[uiUartCmdListNumber++] = pUartCmdList;
    return TRUE;
}

void UartCommandInit(void)
{
    UartRegisterUartCmdList(sUartCommand);
}

static int UartCmdRemoveBackSpace( char* szString )
{
    char*   ptr = szString;
    int     i=0;

    while(*ptr) {
        if(*ptr == 0x08) {
            if( i>0 ) {
                i--;
            }
            ptr++;
            continue;
        }
        szString[i] = *ptr;
        ptr++;
        i++;
    }
    szString[i] = '\0';	
    return i;
}

const char divider[] = 
{
    ' ','\t','\0','\n'
};

MMP_BOOL IsDivider( char ch )
{
    int i;
    for(i=0; i<sizeof(divider); i++) {
        if(ch == divider[i]) {
            return TRUE;
        }
    }
    return FALSE;
}

int UartCmdLenth( char* pCmd )
{
    int i=0;
    while(!IsDivider(*pCmd++)) {
        i++;
    }

    return i;
}

MMP_BOOL UartCmdCompare( char* pSrcCmd, char* pDstCmd )
{
    int iLength = 0;
    int iLength2 = 0;

    iLength = UartCmdLenth(pDstCmd);
    iLength2 = strlen(pSrcCmd);
    if(iLength != iLength2) {
        return FALSE;
    }

    if(strncmp( pSrcCmd, pDstCmd, iLength )==0) {
        return TRUE;
    }
    return FALSE;
}

PUARTCOMMAND UartFindCommand( char* szCommand )
{
    int i;

    EAT_WHITE(szCommand);

    for(i=0; i< uiUartCmdListNumber; i++) {
        PUARTCOMMAND psCmd = sUartCmdListArray[i];

        while(psCmd->szCommandString != NULL) {
            if(UartCmdCompare(psCmd->szCommandString , szCommand)) {
        	    return psCmd;
            }
            psCmd++;
        }
    }
    return NULL;
}

MMP_BOOL UartExecuteCommandEx( char* szCommand )
{
    PUARTCOMMAND psCmd;
    MMP_BOOL  bFoundCommand = FALSE;

    EAT_WHITE(szCommand);

    psCmd = UartFindCommand(szCommand);

    if(psCmd != NULL) {
        int iCommandLength = UartCmdLenth(szCommand);
        bFoundCommand = TRUE;
        psCmd->pFunc(&szCommand[iCommandLength]);
    }
    return bFoundCommand;
}
#ifdef ZDW_BARCODE
extern MMP_BOOL bToSucceedMode;
#endif
//------------------------------------------------------------------------------
//  Function    : RTNA_DBG_RxCallback
//  Description : Callback to handle input data via FIFO port
//------------------------------------------------------------------------------
void RTNA_DBG_RxCallback(MMP_UBYTE size, volatile MMP_UBYTE *fifo)
{
    MMP_LONG i;
    MMP_BYTE rx_byte;
	
    for(i = 0; i < size; i++) {
        rx_byte = *fifo;
        m_bDebugRxStrBuf[(m_bDebugRxStrLen + i) % RX_QUEUE_SIZE] = rx_byte;
        // Uart Echo
        //MMPF_Uart_Write(DEBUG_UART_NUM, &rx_byte, 1);
    }
    m_bDebugRxStrLen += size;
    if (m_bDebugRxStrLen >= RX_QUEUE_SIZE) {
        m_bDebugRxStrLen = 0;
        //RTNA_DBG_Str(4, "Error: UART RX overflow\r\n");
		debug_printf(0, "Error: UART RX overflow");
    }
#ifdef ZDW_BARCODE
	//MMPF_Uart_Write(DEBUG_UART_NUM, "\r\n", 1);

	if(m_bDebugRxStrLen>=6){
		
	//MMPF_Uart_Write(DEBUG_UART_NUM, m_bDebugRxStrBuf, m_bDebugRxStrLen);
		m_bDebugRxStrLen = 0;
	}else{
				//KK_Debug4(m_bDebugRxStrBuf); 
		for(i = 0 ; i < m_bDebugRxStrLen ; i++){
			if(m_bDebugRxStrBuf[i] == 'D')
				m_bDebugRxStrLen = 0;
		}
	}

#endif
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_GetDebugString
//  Description : This function will send back the string until the user enter the "Enter"
//  Note        :
//------------------------------------------------------------------------------
MMP_ERR MMPF_Uart_GetDebugString(MMPF_UART_ID uartId, MMP_BYTE *bDebugString, MMP_ULONG *ulDebugStringLength)
{
    MMP_LONG i;
    MMP_BOOL bEnterDetect = MMP_FALSE;

    m_bDebugRxStrLen = 0;
    if (MMPF_Uart_IsRxEnable(uartId) == MMP_FALSE) {
        MMPF_Uart_EnableRx(uartId, 1, (UartCallBackFunc *)&RTNA_DBG_RxCallback);
    }

    do {
        for(i = m_bDebugRxStrLen; i >= 0; i--) {
            if(m_bDebugRxStrBuf[i] == RX_ENTER_SIGNAL) {
                *ulDebugStringLength = i;  //Copy string except the "Enter" signal
                MEMCPY(bDebugString, m_bDebugRxStrBuf, i);

                bDebugString[i] = '\0';
                bEnterDetect = MMP_TRUE;
                MEMSET0(&m_bDebugRxStrBuf);
                break;
            }
        }
        MMPF_OS_Sleep(RX_SENSITIVE);
    } while(bEnterDetect == MMP_FALSE);

    MMPF_Uart_DisableRx(uartId);
    return MMP_ERR_NONE;
}

MMPF_OS_FLAGID UART_Flag_Hif = 0x1000;
void UartCommandShell(void)
{
    MMP_BYTE    str[128]={0};
    MMP_ULONG   len;
    MMP_BOOL    bCommandFound = FALSE;
    MMP_BOOL    bExitShell    = FALSE;

    MMPF_OS_FLAGS flags;
    MMPF_OS_FLAGS waitFlags = 1;
    extern void MMPF_Uart_Init(void);
    MMPF_Uart_Init();

    while(1) {
       // MMPF_OS_WaitFlags(UART_Flag_Hif, waitFlags, MMPF_OS_FLAG_WAIT_SET_ANY | OS_FLAG_CONSUME, 0, &flags);
        RTNA_DBG_Str0("UART>");

        MMPF_Uart_GetDebugString(DEBUG_UART_NUM, str, &len);
        str[len] = '\0';

        // Remove next line
        {
            int n;
            for( n=0; n<len; n++ ) {
                if(str[n] == 0x0D)
                    str[n] = '\0';
            }
        }
        UartCmdRemoveBackSpace(str);
        RTNA_DBG_Str0("\n");

        if(strlen(str) == 0) {
            continue;
        }

        if(str[0] == 'x') {
            bExitShell = TRUE;
        }
//ZDW
        //if(bExitShell) {
        //    break;
        //}

        bCommandFound = UartExecuteCommandEx(str);
        if(!bCommandFound) {
            RTNA_DBG_Str0("The command is a invalid!\r\n");
        }
        //MMPF_OS_SetFlags(UART_Flag_Hif, 1, MMPF_OS_FLAG_SET);
		MMPF_OS_Sleep(1);
    }
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_Close
//  Description : Return if RX is enabled with the specified UART ID
//  Note        :
//------------------------------------------------------------------------------
MMP_BOOL MMPF_Uart_IsRxEnable(MMPF_UART_ID uart_id)
{
    if (uart_id < MMPF_UART_MAX_COUNT)
        return m_UartRxEnable[uart_id];
    else
        return MMP_FALSE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_EnableRx
//  Description : Enable RX with the specified UART ID, set interrupt threshold
//  Note        :
//------------------------------------------------------------------------------
MMP_ERR MMPF_Uart_EnableRx(MMPF_UART_ID uartId, MMP_ULONG threshold, UartCallBackFunc *callBackFunc)
{
    AITPS_UARTB pUART = AITC_BASE_UARTB;

    if (uartId >= MMPF_UART_MAX_COUNT)
        return MMP_UART_ERR_PARAMETER;
    else if (threshold > 32)
        return MMP_UART_ERR_PARAMETER;

    if (m_UartRxEnable[uartId] == MMP_FALSE) {
        if (MMPF_OS_AcquireSem(m_UartSemID[uartId], UART_RXINT_SEM_TIMEOUT) == 0) {
            m_UartRx_CallBack[uartId] = callBackFunc;

            // Disable FIFO interrupt first before reset FIFO threshold
            pUART->US[uartId].US_IER &= ~(US_RX_FIFO_OVER_THRES);

            pUART->US[uartId].US_FTHR &= ~(US_RX_FIFO_THRES_MASK);
            pUART->US[uartId].US_FTHR |= US_RX_FIFO_THRES(threshold);

            // Enable receiver and Rx FIFO interrupt
            pUART->US[uartId].US_CR |= US_RXEN;
            pUART->US[uartId].US_IER |= US_RX_FIFO_OVER_THRES;
            MMPF_OS_ReleaseSem(m_UartSemID[uartId]);
        }
        else {
            return MMP_UART_SYSTEM_ERR;
        }
        m_UartRxEnable[uartId] = MMP_TRUE;
    }
    return MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_DisableRx
//  Description : Disable RX with the specified UART ID
//  Note        :
//------------------------------------------------------------------------------
MMP_ERR MMPF_Uart_DisableRx(MMPF_UART_ID uartId)
{
    AITPS_UARTB pUART = AITC_BASE_UARTB;

    if (uartId >= MMPF_UART_MAX_COUNT)
        return MMP_UART_ERR_PARAMETER;

    if (m_UartRxEnable[uartId]) {
        if (MMPF_OS_AcquireSem(m_UartSemID[uartId], UART_RXINT_SEM_TIMEOUT) == 0) {
            pUART->US[uartId].US_IER &= ~(US_RX_FIFO_OVER_THRES);
            pUART->US[uartId].US_CR &= ~(US_RXEN);

            m_UartRx_CallBack[uartId] = NULL;
            MMPF_OS_ReleaseSem(m_UartSemID[uartId]);
        }
        else {
            return MMP_UART_SYSTEM_ERR;
        }

        // Reset receiver
	    pUART->US[uartId].US_CR |= US_RSTRX;

        m_UartRxEnable[uartId] = MMP_FALSE;

        pUART->US[uartId].US_CR &= ~(US_RSTRX);
    }
    return MMP_ERR_NONE;
}
#endif

//------------------------------------------------------------------------------
//  Function    : MMPF_UART_ISR
//  Description :
//  Note        :
//------------------------------------------------------------------------------
void MMPF_UART_ISR(void)
{
    MMP_ULONG   len, i;
    MMP_USHORT  intsrc;
    AITPS_UARTB pUART = AITC_BASE_UARTB;

    for (i = 0; i < 1/*MMPF_UART_MAX_COUNT*/; i++) {
        intsrc = pUART->US[i].US_ISR & pUART->US[i].US_IER;
        pUART->US[i].US_ISR = intsrc;

        #if (UART_RXINT_MODE_EN == 1)
        if ((m_UartInDmaMode[i] == MMP_FALSE) && (intsrc & US_RX_FIFO_OVER_THRES)) {

            len = (pUART->US[i].US_FSR & US_RX_FIFO_UNRD_MASK) >> 4;

            if((m_UartRx_CallBack[i] != NULL) && len)
                (*m_UartRx_CallBack[i])((MMP_UBYTE)len, &pUART->US[i].US_RXPR);
            break;
        }
        else if (intsrc & US_RX_PARITY_ERR) {
            RTNA_DBG_Str(0, "Error: US_RX_PARITY_ERR\r\n");
            break;
        }
        #endif

        #if (UART_DMA_MODE_EN == 1)
        if (intsrc & US_TXDMA_FINISH_IENABLE) {
            if ((m_UartDma_CallBack[i] != NULL) && (m_UartInDmaMode[i] == MMP_TRUE)) {
                (*m_UartDma_CallBack[i]) (MMPF_UART_TXDMA_FINISH_IENABLE);
            }	
        }
        else if (intsrc & US_RXDMA_THR_IEABLE) {
            if ((m_UartDma_CallBack[i] != NULL) && (m_UartInDmaMode[i] == MMP_TRUE)) {
                (*m_UartDma_CallBack[i]) (MMPF_UART_RXDMA_THR_IEABLE);
            }
        }
        else if (intsrc & US_RXDMA_WRITEMEM_IENALBE) {
            if ((m_UartDma_CallBack[i] != NULL) && (m_UartInDmaMode[i] == MMP_TRUE)){
                (*m_UartDma_CallBack[i]) (MMPF_UART_RXDMA_WRITEMEM_IENALBE);
            }
        }
        else if (intsrc & US_RXDMA_DROPDATA_IENALBE) {
            if ((m_UartDma_CallBack[i] != NULL) && (m_UartInDmaMode[i] == MMP_TRUE)){
                (*m_UartDma_CallBack[i]) (MMPF_UART_RXDMA_DROPDATA_IENALBE);
            }
        }
        #endif
    }
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_Init
//  Description : Initial the semaphore and call-back functions.
//  Note        :
//------------------------------------------------------------------------------
MMP_ERR MMPF_Uart_Init(void)
{
#if UART_DBG_EN && UART_RXINT_MODE_EN
    static MMP_BOOL bUartInitFlag = MMP_FALSE;
    AITPS_AIC   pAIC  = AITC_BASE_AIC;
    MMP_USHORT 	i = 0;

    if (!bUartInitFlag) {
        RTNA_AIC_Open(pAIC, AIC_SRC_UART,   uart_isr_a,
                        AIC_INT_TO_IRQ | AIC_SRCTYPE_HIGH_LEVEL_SENSITIVE | 3);
        RTNA_AIC_IRQ_En(pAIC, AIC_SRC_UART);

        for (i = 0; i < MMPF_UART_MAX_COUNT; i++) {
            m_UartSemID[i]          = MMPF_OS_CreateSem(1);
            m_UartInDmaMode[i]      = MMP_FALSE;
            #if UART_RXINT_MODE_EN
            m_UartRxEnable[i]       = MMP_FALSE;
            m_UartRx_CallBack[i]    = NULL;
            #endif
            #if UART_DMA_MODE_EN
            m_UartDma_CallBack[i]   = NULL;
            #endif
        }

        bUartInitFlag = MMP_TRUE;
        MMPF_OS_ReleaseSem(m_UartSemID[0]);

        if(MMPF_OS_AcquireSem(m_UartSemID[0], UART_RXINT_SEM_TIMEOUT) == 0) {
            RTNA_DBG_Str0("UART enable interrupt! \r\n");
        }
        else {
            RTNA_DBG_Str0("[Error] UART enable interrupt fail! \r\n");
        }
    }
#endif
    return	MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_Open
//  Description :
//  Note        :
//------------------------------------------------------------------------------
MMP_ERR    MMPF_Uart_Open(MMPF_UART_ID uartId, MMPF_UART_ATTRIBUTE *uartattribute)
{
    #if(UART_DBG_EN == 0x1)
    AITPS_UARTB pUART = AITC_BASE_UARTB;
    AITPS_GBL 	pGBL  = AITC_BASE_GBL;
//ZDW_BARCODE
	 MMP_ULONG uart_Status = 0;
    // PAD config for UART interface
    // Clean PAD config first.
//ZDW_BARCODE
	 uart_Status = pUART->US[uartId].US_CR & US_RXEN;
    pGBL->GBL_IO_CTL1 &= ~(GBL_UART_TX_PAD0 | GBL_UART_TX_PAD1);
    pGBL->GBL_IO_CTL3 &= ~(GBL_UART_RX_PAD0 | GBL_UART_RX_PAD1 | GBL_UART_RX_PAD2 | GBL_UART_TX_PAD2);

    switch(uartattribute->padset) {
        case MMPF_UART_PADSET_0:	// use AGPIO0 as uart TX
            pGBL->GBL_IO_CTL1 |= GBL_UART_TX_PAD0;
            #if (UART_RXINT_MODE_EN == 0x1)
            pGBL->GBL_IO_CTL3 |= GBL_UART_RX_PAD0;
            #endif
            break;
        case MMPF_UART_PADSET_1:	// use PSNR_D8 as uart TX
            pGBL->GBL_IO_CTL1 |= GBL_UART_TX_PAD1;
            #if (UART_RXINT_MODE_EN == 0x1)
            pGBL->GBL_IO_CTL3 |= GBL_UART_RX_PAD1;
            #endif
            break;
        case MMPF_UART_PADSET_2:	// use BGPIO14 as uart tx
            pGBL->GBL_IO_CTL3 |= GBL_UART_TX_PAD2;
            #if (UART_RXINT_MODE_EN == 0x1)
            pGBL->GBL_IO_CTL3 |= GBL_UART_RX_PAD2;
            #endif
            break;
        default:
            RTNA_DBG_Str(0, "Un-supported uart PAD !!\r\n");
            return MMP_UART_ERR_PARAMETER;
            break;
    };

    MMPF_Uart_Close(uartId);

    // Define the baud rate divisor register
    pUART->US[uartId].US_BRGR = (((uartattribute->ulMasterclk << 1) / uartattribute->ulBaudrate) + 1) >> 1;
    // Define the USART mode 8-N-1
   // pUART->US[uartId].US_CR = US_ASYNC_MODE | US_TXEN;
//ZDW_BARCODE
	pUART->US[uartId].US_CR = uart_Status | US_ASYNC_MODE | US_TXEN;

    pUART->US[uartId].US_FTHR &= ~(US_RX_FIFO_THRES_MASK);
    pUART->US[uartId].US_FTHR |= US_RX_FIFO_THRES(1);
    pUART->US[uartId].US_IER = US_RX_FIFO_OVER_THRES;
    #endif //#if(UART_DBG_EN == 0x1)
    return	MMP_ERR_NONE;
}

//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_Write
//  Description : Debug output a string
//------------------------------------------------------------------------------

MMP_ERR    MMPF_Uart_Write(MMPF_UART_ID uartId, char *str, MMP_ULONG ulLength)
{
    #if(UART_DBG_EN == 0x1)
    AITPS_UARTB	pUART  = AITC_BASE_UARTB;
    MMP_ULONG	i, txcnt;

    if(ubDisableUartSW)
        return	MMP_ERR_NONE;

    while (ulLength) {
        txcnt = (pUART->US[uartId].US_FSR & US_TX_FIFO_UNWR_MASK);
        if (txcnt) {
            if (txcnt > ulLength) {
                txcnt = ulLength;
            }
            for (i = 0; i < txcnt; i++) {
                pUART->US[uartId].US_TXPR = *str++;
            }
            ulLength -= txcnt;
        }
    }
    #endif //#if(UART_DBG_EN == 0x1)
    return	MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_Write
//  Description : Debug output uint8_t
//------------------------------------------------------------------------------

MMP_ERR    MMPF_Uart_Write_uint8_t(MMPF_UART_ID uartId, uint8_t *str, MMP_ULONG ulLength)
{
    #if(UART_DBG_EN == 0x1)
    AITPS_UARTB	pUART  = AITC_BASE_UARTB;
    MMP_ULONG	i, txcnt;

    if(ubDisableUartSW)
        return	MMP_ERR_NONE;

    while (ulLength) {
        txcnt = (pUART->US[uartId].US_FSR & US_TX_FIFO_UNWR_MASK);
        if (txcnt) {
            if (txcnt > ulLength) {
                txcnt = ulLength;
            }
            for (i = 0; i < txcnt; i++) {
                pUART->US[uartId].US_TXPR = *str++;
            }
            ulLength -= txcnt;
        }
    }
    #endif //#if(UART_DBG_EN == 0x1)
    return	MMP_ERR_NONE;
}
//------------------------------------------------------------------------------
//  Function    : MMPF_Uart_Close
//  Description :
//  Note        :
//------------------------------------------------------------------------------
MMP_ERR    MMPF_Uart_Close(MMPF_UART_ID uartId)
{
    #if(UART_DBG_EN == 0x1)
    AITPS_UARTB   pUART  = AITC_BASE_UARTB;

    // Disable interrupts
    pUART->US[uartId].US_IER = 0;

    // Reset receiver and transmitter
    pUART->US[uartId].US_CR = US_RSTRX | US_RSTTX | US_RXDIS | US_TXDIS;
    #endif //#if(UART_DBG_EN == 0x1)
    return	MMP_ERR_NONE;
}